package com.internetCafes.spms.web.sys.oauth2;

import com.internetCafes.spms.web.sys.model.UserInfo;
import com.internetCafes.spms.web.sys.model.UserTokenInfo;
import com.internetCafes.spms.web.sys.service.ShiroService;
import com.internetCafes.spms.web.sys.service.UserTokenInfoService;
import com.internetCafes.spms.web.tenant.service.LandingTimeInfoService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Set;

/**
 * 认证
 *
 * @author Sunny
 * @email rekeeper2011@hotmail.com
 * @date 2017-05-20 14:00
 */
@Component
public class OAuth2Realm extends AuthorizingRealm {

    @Value("${spring.pages.expire}")
    private int expire;

    @Autowired
    private ShiroService shiroService;

    @Autowired
    private UserTokenInfoService userTokenInfoService;

    @Autowired
    private LandingTimeInfoService landingTimeInfoService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token;
    }

    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UserInfo user = (UserInfo)principals.getPrimaryPrincipal();
        Long userId = user.getId();

        //用户权限列表
        Set<String> permsSet = shiroService.getUserPermissions(userId);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    /*@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String accessToken = (String) token.getPrincipal();

        //根据accessToken，查询用户信息
        UserTokenInfo tokenEntity = shiroService.queryByToken(accessToken);
        //token失效
        if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
            throw new IncorrectCredentialsException("token失效，请重新登录");
        }else{
            //当前时间
            Date now = new Date();
            tokenEntity.setUpdateTime(now);
            //过期时间
            tokenEntity.setExpireTime(new Date(now.getTime() + expire * 1000));
            userTokenInfoService.update(tokenEntity);
            LandingTimeInfo l = landingTimeInfoService.findLastest(tokenEntity.getUserId());
            if(l == null || l.getUpdateTime().getTime() + expire * 1000 < now.getTime()){
                landingTimeInfoService.save(new LandingTimeInfo(tokenEntity.getUserId(), now, now));
            } else {
                l.setExpire(l.getExpire() + (now.getTime() - l.getUpdateTime().getTime())/1000);
                l.setUpdateTime(now);
                landingTimeInfoService.update(l);
            }
        }

        //查询用户信息
        UserInfo user = shiroService.queryUser(tokenEntity.getUserId());
        //账号锁定
        if(user.getStatus() == 0){
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
        return info;
    }*/

    /**
     * 认证(登录时调用)-redis版
     * 1、根据token值到redis缓存中寻找UserTokenInfo实体类对象。
     * 2、根据用户id到redis缓存中寻找用户信息。如果用户不存在状态为不可用状态则抛出LockedAccountException
     * 3、如果UserTokenInfo对象不存在或者超过有效时间，抛出IncorrectCredentialsException
     * 4、如果UserTokenInfo对象存在则对redis缓存进行更新，并对数据库中的用户登录信息表进行更新。
     * 5、创建或更新用户登录信息表
     * 6、返回SimpleAuthenticationInfo实体类对象
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String accessToken = (String) token.getPrincipal();
        //根据accessToken，查询token信息
        UserTokenInfo tokenEntity = userTokenInfoService.queryByToken(accessToken);
        if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
            //token失效
            throw new IncorrectCredentialsException("token失效，请重新登录");
        }
        //查询用户信息
        UserInfo user = shiroService.queryUser(tokenEntity.getUserId());
        //账号锁定
        if(user==null||user.getStatus() == 0) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }else{
            //当前时间
            Date nowDate = new Date();
            tokenEntity.setUpdateTime(nowDate);
            //过期时间
            tokenEntity.setExpireTime(new Date(nowDate.getTime() + expire * 1000));
            userTokenInfoService.update(tokenEntity);
            landingTimeInfoService.saveOrUpdateLoginLog(tokenEntity.getUserId(),nowDate);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
        return info;
    }
}
